package org.erp.product.infrastructure.mq.listener;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.erp.common.constant.RabbitmqConstant;
import org.erp.common.enums.ProductEvent;
import org.erp.common.redis.service.RedisService;
import org.erp.product.domain.dto.ConsumeMessageDto;
import org.erp.product.domain.entity.ConnectLog;
import org.erp.product.domain.entity.ProductInfo;
import org.erp.product.infrastructure.config.ConnectStateFlow;
import org.erp.product.infrastructure.config.InspectionStateFlow;
import org.erp.product.infrastructure.constant.ProductRedisConstant;
import org.erp.product.infrastructure.convert.ConnectConvert;
import org.erp.product.infrastructure.enums.*;
import org.erp.product.infrastructure.exception.ProductException;
import org.erp.product.infrastructure.mapper.ProductInfoMapper;
import org.erp.product.service.ConnectLogService;
import org.erp.product.service.ProductInfoService;
import org.erp.product.service.TransferLogService;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Log4j2
@AllArgsConstructor
@Component
public class ProductEventListener {

    private final ProductInfoService productInfoService;

    private final ProductInfoMapper productInfoMapper;

    private final ConnectLogService connectLogService;

    private final RedisService redisService;

    private final TransferLogService transferLogService;

    private final ConnectConvert connectConvert;


    @RabbitListener(queues = RabbitmqConstant.ERP_PRODUCT_QUEUE,
            containerFactory = "rabbitListenerContainerFactory")
    @Transactional(rollbackFor = Exception.class)
    public void handleBatchStatusUpdateMessage(String message,
                                               Channel channel,
                                               @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
        ConsumeMessageDto consumeMessageDto = JSONObject.parseObject(message, ConsumeMessageDto.class);
        List<Long> stockIds = consumeMessageDto.getStockIds();
        log.info("收到批量状态更新MQ消息，数量：{}，目标事件：{}，操作人：{}"
                , stockIds.size()
                , consumeMessageDto.getProductEvent().getMessage()
                , consumeMessageDto.getOperationName());
        String key = ProductRedisConstant.PRODUCT_EVENT_LISTENER + consumeMessageDto.getUuid();
        try {
            Boolean first = redisService.setIfAbsent(key, "1", 10, TimeUnit.MINUTES);
            if (Boolean.FALSE.equals(first)) {
                channel.basicAck(deliveryTag, false);
                log.warn("重复批量状态更新消息，已忽略，批次号：{}，操作人：{}",
                        consumeMessageDto.getUuid(), consumeMessageDto.getOperationName());
                return;
            }
            if (ProductEvent.CONFIRM_OVERRULE.equals(consumeMessageDto.getProductEvent())) {
                ConnectLog connectLog = connectLogService.list(new QueryWrapper<ConnectLog>().lambda()
                        .in(ConnectLog::getStockId, stockIds).orderByDesc(ConnectLog::getCreateTime)).get(0);
                ConnectStateFlow.next(ConnectStatusEnum.getByCode(connectLog.getNewStatus()), ConnectEventEnum.CONFIRM_THE_REFUSAL);
                ConnectLog reCreateList = connectConvert.copyReCreate(connectLog);
                connectLogService.save(reCreateList);
                channel.basicAck(deliveryTag, false);
            } else if (ProductEvent.CONFIRM_RETURN.equals(consumeMessageDto.getProductEvent())) {
                List<ProductInfo> productInfoList = productInfoService.list(new QueryWrapper<ProductInfo>().lambda()
                        .in(ProductInfo::getStockId, stockIds));
                Map<EventCodeEnum, List<ProductInfo>> listMap = productInfoList.stream()
                        .collect(Collectors.groupingBy(p -> EventCodeEnum.getByCode(p.getTransferType())));
                if (null != listMap.get(EventCodeEnum.REPAIR)) {
                    List<ProductInfo> repairList = listMap.get(EventCodeEnum.REPAIR);
//                    Integer oldStatus = repairList.get(0).getRepairStatus();
//                    for (ProductInfo productInfo : repairList) {
//                        try {
//                            RepairStatusEnum nextStatus = RepairStateFlow.next(RepairStatusEnum.getByCode(productInfo.getRepairStatus()), RepairEventEnum.CONFIRM_RETURN);
//                            productInfo.setRepairStatus(nextStatus.getCode());
//                        } catch (Exception e) {
//                            throw new ProductException("维修调拨id为: " + productInfo.getId() + " 状态不允许执行该操作");
//                        }
//                    }
//                    Integer newStatus = repairList.get(0).getRepairStatus();
//                    productInfoMapper.updateRepairBatchById(repairList);
                    // 加操作记录
//                    List<TransferLog> transferLogList = TransferLog.getTransferLogList(repairList, oldStatus, newStatus);
//                    transferLogService.saveBatch(transferLogList);
                }
                if (null != listMap.get(EventCodeEnum.INSPECTION)) {
                    List<ProductInfo> inspectionList = listMap.get(EventCodeEnum.INSPECTION);
                    Integer oldStatus = inspectionList.get(0).getInspectionStatus();
                    for (ProductInfo productInfo : inspectionList) {
                        try {
                            InspectionStatusEnum nextStatus = InspectionStateFlow.next(InspectionStatusEnum.getByCode(productInfo.getInspectionStatus()), InspectionEventEnum.CONFIRM_RETURN);
                            productInfo.setInspectionStatus(nextStatus.getCode());
                        } catch (Exception e) {
                            throw new ProductException("质检调拨id为: " + productInfo.getId() + " 状态不允许执行该操作");
                        }
                    }
                    Integer newStatus = inspectionList.get(0).getInspectionStatus();
                    productInfoMapper.updateInspectionBatchById(inspectionList);
                    // 加操作记录
//                    List<TransferLog> transferLogList = TransferLog.getTransferLogList(inspectionList, oldStatus, newStatus);
//                    transferLogService.saveBatch(transferLogList);
                }
                channel.basicAck(deliveryTag, false);
            } else {
                channel.basicReject(deliveryTag, false);
            }
        } catch (Exception e) {
            log.error("批量状态更新处理异常，错误：{}", e.getMessage(), e);
            try {
                redisService.deleteObject(key);
            } catch (Exception ignore) {
            }
            channel.basicReject(deliveryTag, false);
            throw e;
        }
    }
}
